game2006/server/gameserver/base_agent.cc
aozhiwei f4604568f6 1
2023-06-08 18:58:27 +08:00

462 lines
15 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 "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_->event_cb) {
#ifdef DEBUG1
DumpBt(this);
#endif
bool has_event = false;
coroutine_->event_cb(true, has_event);
if (has_event) {
status_= behaviac::BT_INVALID;
auto old_coroutine = coroutine_;
coroutine_ = nullptr;
GetOwner()->shot_hold = false;
old_coroutine->event_cb(false, has_event);
old_coroutine = nullptr;
#ifdef DEBUG1
a8::XPrintf("FireEvent OnAttacked\n", {});
#endif
}
}
}
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_->name;
#endif
status_ = behaviac::BT_RUNNING;
return status_;
}
behaviac::EBTStatus BaseAgent::CoAttackTarget(int target_id)
{
if (status_ == behaviac::BT_RUNNING) {
return DoRunningCb();
}
Entity* entity = GetOwner()->room->GetEntityByUniId(target_id);
if (!entity || !entity->IsCreature(GetOwner()->room)) {
return behaviac::BT_FAILURE;
}
CreatureWeakPtr target = ((Creature*)entity)->GetWeakPtrRef();
if (target.Get()->dead) {
return behaviac::BT_FAILURE;
}
auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED
(
CreatureWeakPtr owner;
CreatureWeakPtr target;
long long frameno = 0;
long long last_pursuit_frameno = 0;
);
context->owner = GetOwner()->GetWeakPtrRef();
context->target = target;
context->frameno = GetOwner()->room->GetFrameNo();
context->last_pursuit_frameno = GetOwner()->room->GetFrameNo();
auto co = std::make_shared<BtCoroutine>(context, "CoAttackTarget");
co->runing_cb =
[this, context] ()
{
if (GetOwner()->room->GetFrameNo() - context->frameno > SERVER_FRAME_RATE * 10 ||
!context->target.Get() || context->target.Get()->dead) {
GetOwner()->shot_hold = false;
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 use_skill_ok = false;
if (context->target.Get() &&
!context->target.Get()->dead) {
int skill_id = GetUseableSkill(context->target.Get());
if (skill_id >= 0) {
GetOwner()->shot_hold = false;
int wait_time = 0;
use_skill_ok = InternalUseSkill(skill_id, context->target, wait_time);
if (use_skill_ok) {
Sleep(wait_time);
}
}
}
#ifdef DEBUG1
if (context->target.Get()->IsPlayer()) {
a8::XPrintf("DoAttack %d use_skill_ok:%d time:%d\n",
{GetOwner()->GetUniId(),
use_skill_ok ? 1 : 0,
GetOwner()->GetMainSkill() ? GetOwner()->GetMainSkill()->GetLeftTime() : 0
});
}
#endif
if (!use_skill_ok) {
bool shot_ok = false;
glm::vec3 shot_dir = dir;
GetOwner()->SetAttackDir(dir);
GetOwner()->shot_hold = true;
GetOwner()->Shot(shot_dir, shot_ok, 0, 0);
}
} else {
GetOwner()->shot_hold = false;
}
}
}
return behaviac::BT_RUNNING;
};
co->event_cb =
[this, context]
(bool is_test, bool& has_event) mutable
{
};
return StartCoroutine(co);
}
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;
}
behaviac::EBTStatus BaseAgent::DoIdle(int min_time, int max_time)
{
if (status_ == behaviac::BT_RUNNING) {
return DoRunningCb();
}
auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED
(
CreatureWeakPtr owner;
a8::XTimerWp timer_ptr;
CreatureWeakPtr last_attacker;
long long last_attacked_frameno = 0;
std::weak_ptr<EventHandlerPtr> handler;
);
context->owner = GetOwner()->GetWeakPtrRef();
context->timer_ptr = GetOwner()->room->xtimer.SetTimeoutWpEx
(
a8::RandEx(min_time, max_time) / FRAME_RATE_MS,
[] (int event, const a8::Args* args)
{
},
&GetOwner()->xtimer_attacher);
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<Creature*>(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<BtCoroutine>(context, "CoIdle");
co->runing_cb =
[this, context] ()
{
if (!context->timer_ptr.expired()) {
return behaviac::BT_RUNNING;
} else {
return behaviac::BT_SUCCESS;
}
};
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);
}
bool BaseAgent::CanUseSkill(int skill_id)
{
return false;
}
int BaseAgent::GetUseableSkill(Creature* target)
{
#if 0
if (!target->IsPlayer()) {
return -1;
}
#endif
#ifdef DEBUG
#if 1
if (GetOwner()->IsHuman()) {
return -1;
}
#endif
#endif
if (GetOwner()->GetHeroMeta() && GetOwner()->GetHeroMeta()->id() == 60100) {
for (int skill_id : mt::Param::s().boss_skill_order) {
Skill* skill = GetOwner()->GetSkill(skill_id);
if (skill && GetOwner()->CanUseSkill(skill->GetSkillId())) {
if (skill_id == 60121) {
if (target->GetPos().Distance2D2(GetOwner()->GetPos()) > skill->meta->skill_distance()) {
continue;
}
}
if (!skill->GetMinorType()) {
return skill->GetSkillId();
}
}
}
} else {
Skill* skill = GetOwner()->GetMainSkill();
if (skill && GetOwner()->CanUseSkill(skill->GetSkillId())) {
if (skill->GetMinorType()) {
return -1;
}
return skill->GetSkillId();
}
}
return -1;
}
behaviac::EBTStatus BaseAgent::DoUseSkill(int skill_id)
{
return behaviac::BT_SUCCESS;
}
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) {
a8::XPrintf("agent use skill:%d cd:%f\n", {skill_id, skill->GetCd()});
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;
}
}