278 lines
8.7 KiB
C++
278 lines
8.7 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 "f8/btmgr.h"
|
|
|
|
#include "mt/Equip.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();
|
|
}
|
|
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 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);
|
|
}
|