1515 lines
42 KiB
C++
1515 lines
42 KiB
C++
#include "precompile.h"
|
|
|
|
#include <f8/btmgr.h>
|
|
|
|
#include "hero_agent.h"
|
|
|
|
#include "hero.h"
|
|
#include "room.h"
|
|
#include "movement.h"
|
|
#include "netdata.h"
|
|
#include "glmhelper.h"
|
|
#include "target_agent.h"
|
|
#include "weapon.h"
|
|
#include "mapinstance.h"
|
|
#include "collision.h"
|
|
#include "human.h"
|
|
#include "team.h"
|
|
#include "master_agent.h"
|
|
#include "team_agent.h"
|
|
#include "skill.h"
|
|
#include "loot.h"
|
|
#include "car.h"
|
|
#include "roomobstacle.h"
|
|
#include "weapon.h"
|
|
|
|
#include "mt/Hero.h"
|
|
#include "mt/Equip.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/Map.h"
|
|
|
|
#include "behaviac_generated/types/internal/behaviac_customized_types.h"
|
|
|
|
HeroAgent::HeroAgent():BaseAgent()
|
|
{
|
|
current_target_agent = behaviac::Agent::Create<TargetAgent>();
|
|
master_agent = behaviac::Agent::Create<MasterAgent>();
|
|
team_agent = behaviac::Agent::Create<TeamAgent>();
|
|
INIT_LIST_HEAD(&coroutines_list_);
|
|
}
|
|
|
|
HeroAgent::~HeroAgent()
|
|
{
|
|
{
|
|
f8::BtMgr::Instance()->BtDestory(current_target_agent);
|
|
current_target_agent = nullptr;
|
|
}
|
|
{
|
|
f8::BtMgr::Instance()->BtDestory(master_agent);
|
|
master_agent = nullptr;
|
|
}
|
|
{
|
|
f8::BtMgr::Instance()->BtDestory(team_agent);
|
|
team_agent = nullptr;
|
|
}
|
|
}
|
|
|
|
void HeroAgent::SetOwner(Creature* owner)
|
|
{
|
|
owner_ = owner;
|
|
current_target_agent->SetOwner(owner_);
|
|
master_agent->SetOwner(owner);
|
|
room_agent = owner_->room->GetRoomAgent();
|
|
}
|
|
|
|
int HeroAgent::GetUniId()
|
|
{
|
|
return owner_->GetUniId();
|
|
}
|
|
|
|
int HeroAgent::GetAgentType()
|
|
{
|
|
abort();
|
|
}
|
|
|
|
bool HeroAgent::IsMoving()
|
|
{
|
|
return owner_->GetMovement()->GetPathSize() > 0;
|
|
}
|
|
|
|
glm::vec3 HeroAgent::GetPos()
|
|
{
|
|
return owner_->GetPos().ToGlmVec3();
|
|
}
|
|
|
|
bool HeroAgent::IsDead()
|
|
{
|
|
return owner_->dead;
|
|
}
|
|
|
|
glm::vec3 HeroAgent::GetSafeAreaCenter()
|
|
{
|
|
return glm::vec3(
|
|
owner_->room->GetGasData().pos_new.x,
|
|
0.0f,
|
|
owner_->room->GetGasData().pos_new.y
|
|
);
|
|
}
|
|
|
|
float HeroAgent::GetSafeAreaRadius()
|
|
{
|
|
return owner_->room->GetGasData().gas_progress;
|
|
}
|
|
|
|
float HeroAgent::GetHp()
|
|
{
|
|
return owner_->GetHP();
|
|
}
|
|
|
|
float HeroAgent::GetMaxHp()
|
|
{
|
|
return owner_->GetMaxHP();
|
|
}
|
|
|
|
void HeroAgent::OpenBulletTraceMode()
|
|
{
|
|
bullet_trace_mode_ = true;
|
|
}
|
|
|
|
void HeroAgent::CloseBulletTraceMode()
|
|
{
|
|
bullet_trace_mode_ = false;
|
|
}
|
|
|
|
float HeroAgent::CalcDistance(const glm::vec3& target_pos)
|
|
{
|
|
return owner_->GetPos().DistanceGlmVec3(target_pos);
|
|
}
|
|
|
|
int HeroAgent::GetHeroId()
|
|
{
|
|
return owner_->GetHeroMeta()->id();
|
|
}
|
|
|
|
int HeroAgent::GetLevel()
|
|
{
|
|
return owner_->level;
|
|
}
|
|
|
|
bool HeroAgent::CanShot()
|
|
{
|
|
if (owner_->GetActionType() == AT_Reload) {
|
|
return false;
|
|
}
|
|
if (owner_->GetCar() && owner_->IsHuman() &&
|
|
!owner_->GetCar()->CanShot(owner_->AsHuman())) {
|
|
return false;
|
|
}
|
|
return owner_->CanShot(true);
|
|
}
|
|
|
|
bool HeroAgent::CanUseSkill(int skill_id)
|
|
{
|
|
if (owner_->GetCar()) {
|
|
return false;
|
|
}
|
|
return owner_->CanUseSkill(skill_id);
|
|
}
|
|
|
|
void HeroAgent::SendEmote(int emote)
|
|
{
|
|
owner_->room->frame_event.AddEmote(owner_->GetWeakPtrRef(), emote);
|
|
}
|
|
|
|
int HeroAgent::GetBattleTimes()
|
|
{
|
|
return owner_->GetBattleContext()->GetBattleTimes();
|
|
}
|
|
|
|
void HeroAgent::SetMoveDir(const glm::vec3& dir)
|
|
{
|
|
owner_->SetMoveDir(dir);
|
|
}
|
|
|
|
void HeroAgent::SetAttackDir(const glm::vec3& dir)
|
|
{
|
|
owner_->SetAttackDir(dir);
|
|
if (owner_->GetCar() && owner_->IsHuman() && owner_->GetCar()->IsDriver(owner_->AsHuman())) {
|
|
if (!owner_->GetCar()->HasBuffEffect(kBET_Sprint)) {
|
|
owner_->GetCar()->SetAttackDir(owner_->GetAttackDir());
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeroAgent::ShotNormal(const glm::vec3& dir)
|
|
{
|
|
if (owner_->dead) {
|
|
return;
|
|
}
|
|
if (owner_->CanShot(true)) {
|
|
bool shot_ok = false;
|
|
glm::vec3 shot_dir = owner_->GetAttackDir();
|
|
if (bullet_angle_offset_max_ > 0) {
|
|
GlmHelper::RotateY(shot_dir, a8::RandEx(bullet_angle_offset_min_, bullet_angle_offset_max_)/180.0);
|
|
owner_->SetAttackDir(shot_dir);
|
|
}
|
|
owner_->shot_hold = true;
|
|
if (bullet_trace_mode_) {
|
|
owner_->Shot(shot_dir, shot_ok, 0, 0);
|
|
} else {
|
|
owner_->Shot(shot_dir, shot_ok, 0, 0);
|
|
}
|
|
last_shot_frameno_ = owner_->room->GetFrameNo();
|
|
}
|
|
}
|
|
|
|
void HeroAgent::ShotTrace()
|
|
{
|
|
if (owner_->dead) {
|
|
return;
|
|
}
|
|
if (!current_target_agent->IsValid()) {
|
|
return;
|
|
}
|
|
if (owner_->CanShot(true)) {
|
|
bool shot_ok = false;
|
|
glm::vec3 shot_dir = owner_->GetAttackDir();
|
|
if (bullet_trace_mode_) {
|
|
owner_->Shot(shot_dir, shot_ok, 0, current_target_agent->GetUniId());
|
|
} else {
|
|
owner_->Shot(shot_dir, shot_ok, 0, current_target_agent->GetUniId());
|
|
}
|
|
last_shot_frameno_ = owner_->room->GetFrameNo();
|
|
}
|
|
}
|
|
|
|
glm::vec3 HeroAgent::GetRandomDir()
|
|
{
|
|
glm::vec3 dir = owner_->GetAttackDir();
|
|
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
|
|
return dir;
|
|
}
|
|
|
|
glm::vec3 HeroAgent::GetTargetDir()
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return owner_->GetAttackDir();
|
|
}
|
|
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
|
|
current_target_agent->GetPos())) {
|
|
return owner_->GetAttackDir();
|
|
}
|
|
glm::vec3 dir = current_target_agent->GetPos() - owner_->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(dir);
|
|
return dir;
|
|
}
|
|
|
|
glm::vec3 HeroAgent::RandomPoint(const glm::vec3& center, float range)
|
|
{
|
|
glm::vec3 hit_point;
|
|
bool hit_result = false;
|
|
|
|
glm::vec3 start = center;
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
|
|
GlmHelper::Normalize(dir);
|
|
glm::vec3 end = center + dir * range;
|
|
|
|
owner_->room->map_instance->Scale(start);
|
|
owner_->room->map_instance->Scale(end);
|
|
if (owner_->room->map_instance->Raycast
|
|
(
|
|
start,
|
|
end,
|
|
hit_point,
|
|
hit_result
|
|
)) {
|
|
owner_->room->map_instance->Scale(hit_point);
|
|
}
|
|
return hit_point;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::RandomSafeZonePoint(int try_count, int step_len)
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "RandomSafeZonePoint");
|
|
co->runing_cb =
|
|
[this, context, try_count, step_len] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
glm::vec3 gas_center = GlmHelper::Vec2ToVec3(owner_->room->GetGasData().pos_new);
|
|
gas_center.y = owner_->GetPos().ToGlmVec3().y;
|
|
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
|
|
gas_center)) {
|
|
out_point0 = gas_center;
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
|
|
glm::vec3 dir = gas_center - owner_->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(dir);
|
|
|
|
glm::vec3 center = owner_->GetPos().ToGlmVec3() +
|
|
dir * (50.0f + (float)(try_count + 1) * step_len);
|
|
owner_->room->map_instance->Scale(center);
|
|
glm::vec3 point;
|
|
bool ok = owner_->room->map_instance->FindConnectableNearestPoint(center, 50, point);
|
|
if (ok) {
|
|
owner_->room->map_instance->UnScale(point);
|
|
out_point0 = point;
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
float HeroAgent::GetShotRange()
|
|
{
|
|
if (owner_->GetCurrWeapon()) {
|
|
return owner_->GetCurrWeapon()->meta->range();
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
void HeroAgent::SetV(int id, int val)
|
|
{
|
|
auto itr = dyn_hash_.find(id);
|
|
if (itr != dyn_hash_.end()) {
|
|
itr->second = val;
|
|
} else {
|
|
dyn_hash_[id] = val;
|
|
}
|
|
}
|
|
|
|
int HeroAgent::GetV(int id)
|
|
{
|
|
auto itr = dyn_hash_.find(id);
|
|
if (itr != dyn_hash_.end()) {
|
|
return itr->second;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int HeroAgent::IncV(int id, int val)
|
|
{
|
|
auto itr = dyn_hash_.find(id);
|
|
if (itr != dyn_hash_.end()) {
|
|
itr->second += val;
|
|
return itr->second;
|
|
} else {
|
|
dyn_hash_[id] = val;
|
|
return val;
|
|
}
|
|
}
|
|
|
|
int HeroAgent::DecV(int id, int val)
|
|
{
|
|
return IncV(id, -val);
|
|
}
|
|
|
|
bool HeroAgent::HasBuffEffect(int effect_id)
|
|
{
|
|
return owner_->HasBuffEffect(effect_id);
|
|
}
|
|
|
|
bool HeroAgent::IsNearGas(float anti_range)
|
|
{
|
|
return !Collision::InSquare
|
|
(GlmHelper::Vec2ToVec3(owner_->room->GetGasData().pos_old),
|
|
owner_->GetPos().ToGlmVec3(),
|
|
std::max(owner_->room->GetGasData().rad_new,
|
|
owner_->room->GetGasData().gas_progress) * 0.7 -
|
|
anti_range);
|
|
}
|
|
|
|
bool HeroAgent::MasterInRange(float range)
|
|
{
|
|
if (!owner_->IsHero() ||
|
|
!owner_->AsHero()->master.Get()) {
|
|
return false;
|
|
}
|
|
return Collision::InSquare
|
|
(owner_->AsHero()->master.Get()->GetPos().ToGlmVec3(),
|
|
owner_->GetPos().ToGlmVec3(),
|
|
range);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::SearchEnemy(float range)
|
|
{
|
|
Creature* myself = owner_;
|
|
Creature* target = nullptr;
|
|
float last_distance = range + 1;
|
|
owner_->room->grid_service->TraverseCreatures
|
|
(owner_->room->GetRoomIdx(),
|
|
owner_->GetGridList(),
|
|
[myself, &last_distance, &target, range] (Creature* c, bool& stop)
|
|
{
|
|
if (!c->dead &&
|
|
!a8::HasBitFlag(c->status, CS_Disable) &&
|
|
!c->HasBuffEffect(kBET_Hide) &&
|
|
!c->HasBuffEffect(kBET_Invincible) &&
|
|
c->team_id != myself->team_id &&
|
|
!c->IsCar() &&
|
|
!myself->IsIgnoreTarget(c->GetUniId())) {
|
|
if (a8::HasBitFlag(myself->status, CS_DisableAttackAndroid) &&
|
|
c->IsAndroid()) {
|
|
} else {
|
|
float distance = c->GetPos().Distance2D2(myself->GetPos());
|
|
if (distance <= range) {
|
|
if (distance < last_distance) {
|
|
target = c;
|
|
last_distance = distance;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
if (target) {
|
|
current_target_agent->SetTarget(target);
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
void HeroAgent::SetBulletAngleOffset(int min_val, int max_val)
|
|
{
|
|
bullet_angle_offset_min_ = min_val;
|
|
bullet_angle_offset_max_ = max_val;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::TrySearchEnemy(float range, int min_interval, int max_interval)
|
|
{
|
|
int rnd = a8::RandEx(min_interval, max_interval);
|
|
if ((owner_->room->GetFrameNo() - last_try_search_enemy_frameno_) * FRAME_RATE_MS <
|
|
rnd) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
last_try_search_enemy_frameno_ = owner_->room->GetFrameNo();
|
|
Creature* myself = owner_;
|
|
Creature* target = nullptr;
|
|
float last_distance = range + 1;
|
|
owner_->room->grid_service->TraverseCreatures
|
|
(owner_->room->GetRoomIdx(),
|
|
owner_->GetGridList(),
|
|
[myself, &last_distance, &target, range] (Creature* c, bool& stop)
|
|
{
|
|
if (!c->dead &&
|
|
!a8::HasBitFlag(c->status, CS_Disable) &&
|
|
!c->HasBuffEffect(kBET_Hide) &&
|
|
!c->HasBuffEffect(kBET_Invincible) &&
|
|
c->team_id != myself->team_id &&
|
|
!c->IsCar() &&
|
|
!myself->IsIgnoreTarget(c->GetUniId())) {
|
|
if (a8::HasBitFlag(myself->status, CS_DisableAttackAndroid) &&
|
|
c->IsAndroid()) {
|
|
} else {
|
|
float distance = c->GetPos().Distance2D2(myself->GetPos());
|
|
if (distance <= range) {
|
|
if (distance < last_distance) {
|
|
target = c;
|
|
last_distance = distance;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
if (target) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoIdle(int min_val, int max_val)
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
int time = 0;
|
|
);
|
|
context->time = a8::RandEx(min_val, max_val);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoIdle");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if ((GetRoom()->GetFrameNo() - context->frameno) * FRAME_RATE_MS <
|
|
context->time) {
|
|
return behaviac::BT_RUNNING;
|
|
} else {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoMoveCurrentTargetRaycast()
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoMoveCurrentTargetRaycast");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!current_target_agent->IsValid()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
bool ret = owner_->room->MoveCanReach(owner_->GetPos().ToGlmVec3(),
|
|
current_target_agent->GetPos());
|
|
if (ret) {
|
|
return behaviac::BT_SUCCESS;
|
|
} else {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoShotCurrentTargetRaycast()
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoShotCurrentTargetRaycast");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!current_target_agent->IsValid()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
bool ret = owner_->room->MoveCanReach(owner_->GetPos().ToGlmVec3(),
|
|
current_target_agent->GetPos());
|
|
if (ret) {
|
|
return behaviac::BT_SUCCESS;
|
|
} else {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoMoveMasterRaycast()
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
a8::XTimerWp timer_ptr;
|
|
);
|
|
context->timer_ptr = owner_->room->xtimer.SetTimeoutWpEx
|
|
(
|
|
1000 / FRAME_RATE_MS,
|
|
[] (int event, const a8::Args* args)
|
|
{
|
|
},
|
|
&owner_->xtimer_attacher);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoMoveMasterRaycast");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!context->timer_ptr.expired()) {
|
|
return behaviac::BT_RUNNING;
|
|
} else {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoFindPath(const glm::vec3& pos)
|
|
{
|
|
PRE_ENTER_COROUTINE_EX(kCoFindPath);
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
bool find_ok = false;
|
|
glm::vec3 target_pos;
|
|
);
|
|
context->target_pos = pos;
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoFindPath");
|
|
co->runing_cb =
|
|
[this, context, pos] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
owner_->GetMovement()->ClearPath();
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (context->find_ok) {
|
|
if (owner_->GetMovement()->GetPathSize() <= 0) {
|
|
return behaviac::BT_SUCCESS;
|
|
} else {
|
|
return behaviac::BT_RUNNING;
|
|
}
|
|
}
|
|
bool ret = owner_->GetMovement()->FindPath(context->target_pos, 0);
|
|
if (ret) {
|
|
context->find_ok = true;
|
|
} else {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
return behaviac::BT_RUNNING;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoFindPathEx(const glm::vec3& pos, float distance)
|
|
{
|
|
PRE_ENTER_COROUTINE_EX(kCoFindPathEx);
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
bool find_ok = false;
|
|
glm::vec3 target_pos;
|
|
);
|
|
context->target_pos = pos;
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoFindPathEx");
|
|
co->runing_cb =
|
|
[this, context, distance] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
owner_->GetMovement()->ClearPath();
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (context->find_ok) {
|
|
if (owner_->GetMovement()->GetPathSize() <= 0) {
|
|
return behaviac::BT_SUCCESS;
|
|
} else {
|
|
return behaviac::BT_RUNNING;
|
|
}
|
|
}
|
|
bool ret = owner_->GetMovement()->FindPath(context->target_pos, distance);
|
|
if (ret) {
|
|
context->find_ok = true;
|
|
} else {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
return behaviac::BT_RUNNING;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoStartMove(int min_val, int max_val)
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
float distance = a8::RandEx(min_val, max_val);
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoStartMove");
|
|
co->runing_cb =
|
|
[this, context, distance] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!owner_->dead) {
|
|
owner_->GetMovement()->CalcTargetPos(distance);
|
|
}
|
|
return behaviac::BT_SUCCESS;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoSleep(int time)
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
a8::XTimerWp timer_ptr;
|
|
);
|
|
context->timer_ptr = owner_->room->xtimer.SetTimeoutWpEx
|
|
(
|
|
time / FRAME_RATE_MS,
|
|
[] (int event, const a8::Args* args)
|
|
{
|
|
},
|
|
&owner_->xtimer_attacher);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoSleep");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!context->timer_ptr.expired()) {
|
|
return behaviac::BT_RUNNING;
|
|
} else {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoUseSkill(int skill_id)
|
|
{
|
|
int wait_time = 0;
|
|
if (InternalUseSkill(skill_id, wait_time)) {
|
|
last_useskill_frameno_ = owner_->room->GetFrameNo();
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
Room* HeroAgent::GetRoom()
|
|
{
|
|
return owner_->room;
|
|
}
|
|
|
|
bool HeroAgent::HasFlag(int tag)
|
|
{
|
|
return a8::HasBitFlag(flags_, tag);
|
|
}
|
|
|
|
void HeroAgent::SetFlag(int tag)
|
|
{
|
|
a8::SetBitFlag(flags_, tag);
|
|
}
|
|
|
|
void HeroAgent::UnSetFlag(int tag)
|
|
{
|
|
a8::UnSetBitFlag(flags_, tag);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::RegisterEvents(behaviac::vector<BtEvent_e> events)
|
|
{
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::ClearEvents()
|
|
{
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoMoveForward(int min_val, int max_val)
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
float distance = a8::RandEx(min_val, max_val);
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
owner_->GetMovement()->CalcTargetPos(distance);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoMoveForward");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->GetMovement()->GetPathSize() <= 0) {
|
|
return behaviac::BT_SUCCESS;
|
|
} else {
|
|
return behaviac::BT_RUNNING;
|
|
}
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::DebugOut(std::string msg, int arg0, int arg1, int arg2)
|
|
{
|
|
#ifdef DEBUG
|
|
//a8::XPrintf((msg+"\n").c_str(), {arg0, arg1, arg2});
|
|
std::string data = a8::Format(msg.c_str(),{arg0, arg1, arg2} );
|
|
owner_->room->BroadcastDebugMsg(data);
|
|
#endif
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
|
|
bool HeroAgent::TargetInShotRange()
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return false;
|
|
}
|
|
float shot_range = GetShotRange();
|
|
bool in_square = Collision::InSquare
|
|
(GetPos(),
|
|
current_target_agent->GetPos(),
|
|
shot_range / 0.7);
|
|
if (!in_square) {
|
|
return false;
|
|
}
|
|
return shot_range > owner_->GetPos().DistanceGlmVec3(current_target_agent->GetPos());
|
|
}
|
|
|
|
bool HeroAgent::InTargetShotRange()
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return false;
|
|
}
|
|
float shot_range = current_target_agent->GetShotRange();
|
|
bool in_square = Collision::InSquare
|
|
(GetPos(),
|
|
current_target_agent->GetPos(),
|
|
shot_range / 0.7);
|
|
if (!in_square) {
|
|
return false;
|
|
}
|
|
return shot_range > owner_->GetPos().DistanceGlmVec3(current_target_agent->GetPos());
|
|
}
|
|
|
|
void HeroAgent::ResetShotTimes()
|
|
{
|
|
shot_times_ = 0;
|
|
last_shot_frameno_ = owner_->room->GetFrameNo();
|
|
}
|
|
|
|
void HeroAgent::ResetUseSkillTimes()
|
|
{
|
|
useskill_times_ = 0;
|
|
last_useskill_frameno_ = owner_->room->GetFrameNo();
|
|
}
|
|
|
|
int HeroAgent::GetShotTimes()
|
|
{
|
|
return shot_times_;
|
|
}
|
|
|
|
int HeroAgent::GetUseSkillTimes()
|
|
{
|
|
return useskill_times_;
|
|
}
|
|
|
|
float HeroAgent::GetTargetManhattanDistance()
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return 0;
|
|
}
|
|
Position pos;
|
|
pos.FromGlmVec3(current_target_agent->GetPos());
|
|
return owner_->GetPos().ManhattanDistance2D(pos);
|
|
}
|
|
|
|
std::string HeroAgent::GetSkillBtFile()
|
|
{
|
|
switch (GetHeroId()) {
|
|
case 30100:
|
|
{
|
|
return "skill/30100_hill";
|
|
}
|
|
break;
|
|
case 30200:
|
|
{
|
|
return "skill/30200_yamada";
|
|
}
|
|
break;
|
|
case 30300:
|
|
{
|
|
return "skill/30300_aoi";
|
|
}
|
|
break;
|
|
case 30400:
|
|
{
|
|
return "skill/30400_astral";
|
|
}
|
|
break;
|
|
case 30500:
|
|
{
|
|
return "skill/30500_miffy";
|
|
}
|
|
break;
|
|
case 30600:
|
|
{
|
|
return "skill/30600_canoe";
|
|
}
|
|
break;
|
|
case 30700:
|
|
{
|
|
return "skill/30700_mariana";
|
|
}
|
|
break;
|
|
case 30800:
|
|
{
|
|
return "skill/30800_dragonscale";
|
|
}
|
|
break;
|
|
case 30900:
|
|
{
|
|
return "skill/30900_lazar";
|
|
}
|
|
break;
|
|
case 31000:
|
|
{
|
|
return "skill/31000_kurosawa";
|
|
}
|
|
break;
|
|
case 60100:
|
|
{
|
|
return "skill/60100_leo";
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeroAgent::Abort(behaviac::string msg, behaviac::vector<int> args)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
bool HeroAgent::HasUseableSkill()
|
|
{
|
|
if (owner_->GetCar()) {
|
|
return false;
|
|
}
|
|
return owner_->HasUseableSkill();
|
|
}
|
|
|
|
bool HeroAgent::InternalUseSkill(int skill_id, int& wait_time)
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return false;
|
|
}
|
|
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
|
|
current_target_agent->GetPos())) {
|
|
return false;
|
|
}
|
|
Skill* skill = owner_->GetSkill(skill_id);
|
|
if (skill) {
|
|
wait_time = 500;
|
|
glm::vec3 skill_dir = current_target_agent->GetPos() - owner_->GetPos().ToGlmVec3();
|
|
float skill_distance = GlmHelper::Norm(skill_dir);
|
|
GlmHelper::Normalize(skill_dir);
|
|
|
|
bool use_ok = false;
|
|
switch (skill->GetCurrSkillMeta()->GetMagicId()) {
|
|
case MAGIC_20101_HL:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20701_BAO:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20801_LONG:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20901_XIONG:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_21001_NIU:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
case MAGIC_20201_HX:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20401_MAO:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20601_DJS:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20301_XL:
|
|
{
|
|
skill_distance = a8::RandEx(20, 60);
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_20501_TZ:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
case MAGIC_60100_1_BOSS:
|
|
case MAGIC_60100_2_BOSS:
|
|
case MAGIC_60100_3_BOSS:
|
|
{
|
|
use_ok = true;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
if (use_ok) {
|
|
owner_->DoSkill(skill->GetSkillId(), current_target_agent->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HeroAgent::HasObserver()
|
|
{
|
|
return owner_->IsHuman() && owner_->AsHuman()->HasObserver();
|
|
}
|
|
|
|
int HeroAgent::GetAliveEnemyNum()
|
|
{
|
|
if (owner_->IsHuman()) {
|
|
return std::max(0, owner_->room->RealAliveCount() - owner_->GetTeam()->GetAliveNum());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int HeroAgent::GetLastShotPassTime()
|
|
{
|
|
return (owner_->room->GetFrameNo() - last_shot_frameno_) * FRAME_RATE_MS;
|
|
}
|
|
|
|
int HeroAgent::GetLastUseSkillPassTime()
|
|
{
|
|
return (owner_->room->GetFrameNo() - last_useskill_frameno_) * FRAME_RATE_MS;
|
|
}
|
|
|
|
int HeroAgent::GetLastAttackPassTime()
|
|
{
|
|
return std::min(GetLastShotPassTime(), GetLastUseSkillPassTime());
|
|
}
|
|
|
|
float HeroAgent::GetHPRate()
|
|
{
|
|
return GetHp() / std::max(1.0f, GetMaxHp());
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoGetRunAwayPoint()
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
if (!current_target_agent->IsValid()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
int try_count = 0;
|
|
int step_len = 200;
|
|
);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "CoGetRunAwayPoint");
|
|
co->runing_cb =
|
|
[this, context] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!current_target_agent->IsValid()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (context->try_count >= 3) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
glm::vec3 gas_center = GlmHelper::Vec2ToVec3(owner_->room->GetGasData().pos_new);
|
|
gas_center.y = owner_->GetPos().ToGlmVec3().y;
|
|
if (GlmHelper::IsEqual2D(owner_->GetPos().ToGlmVec3(),
|
|
gas_center)) {
|
|
out_point0 = gas_center;
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
glm::vec3 dir = gas_center - owner_->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(dir);
|
|
|
|
context->step_len = a8::RandEx(200, 260);
|
|
glm::vec3 center = gas_center;
|
|
if (owner_->room->GetGasData().gas_progress > context->step_len + 50) {
|
|
center = gas_center + dir * (owner_->room->GetGasData().gas_progress - context->step_len);
|
|
}
|
|
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 360.0f);
|
|
center = center + dir * (float)context->step_len;
|
|
owner_->room->map_instance->Scale(center);
|
|
glm::vec3 point;
|
|
bool ok = owner_->room->map_instance->FindConnectableNearestPoint(center, 50, point);
|
|
if (ok) {
|
|
owner_->room->map_instance->UnScale(point);
|
|
out_point0 = point;
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
++context->try_count;
|
|
return behaviac::BT_RUNNING;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
bool HeroAgent::TargetInRange(float range)
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return false;
|
|
}
|
|
return Collision::InSquare
|
|
(current_target_agent->GetPos(),
|
|
owner_->GetPos().ToGlmVec3(),
|
|
range);
|
|
}
|
|
|
|
float HeroAgent::GetNewAttackerHPRate()
|
|
{
|
|
return owner_->GetLastAttacker().Get()->GetHP() /
|
|
std::max(1.0f, owner_->GetLastAttacker().Get()->GetMaxHP());
|
|
}
|
|
|
|
bool HeroAgent::GetNewAttackerInRange(float range)
|
|
{
|
|
if (!HasNewAttacker()) {
|
|
return false;
|
|
}
|
|
return Collision::InSquare
|
|
(owner_->GetLastAttacker().Get()->GetPos().ToGlmVec3(),
|
|
owner_->GetPos().ToGlmVec3(),
|
|
range);
|
|
}
|
|
|
|
int HeroAgent::GetNewAttackerPassTime()
|
|
{
|
|
return (owner_->room->GetFrameNo() - owner_->GetLastBeAttackFrameNo()) * FRAME_RATE_MS;
|
|
}
|
|
|
|
bool HeroAgent::HasNewAttacker()
|
|
{
|
|
if (!current_target_agent->IsValid()) {
|
|
return false;
|
|
}
|
|
if (!owner_->GetLastAttacker().Get()) {
|
|
return false;
|
|
}
|
|
return current_target_agent->GetUniId() != owner_->GetLastAttacker().Get()->GetUniId() &&
|
|
owner_->GetLastAttacker().Get()->revive_count == owner_->GetLastAttackerReviveTimes();
|
|
}
|
|
|
|
bool HeroAgent::NewAttackerIsHuman()
|
|
{
|
|
return owner_->GetLastAttacker().Get()->IsHuman();
|
|
}
|
|
|
|
bool HeroAgent::SwitchToNewAttacker()
|
|
{
|
|
if (HasNewAttacker()) {
|
|
current_target_agent->SetTarget(owner_->GetLastAttacker().Get());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int HeroAgent::GetReviveCount()
|
|
{
|
|
return owner_->revive_count;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::CoGetNextMobaModeRoadPoint()
|
|
{
|
|
if (!GetRoom()->IsMobaModeRoom()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
auto& road = GetRoom()->GetMapMeta()->moba_path_points.at(owner_->road_idx);
|
|
glm::vec3 dir = GlmHelper::UP;
|
|
GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f);
|
|
GlmHelper::Normalize(dir);
|
|
if (owner_->point_idx < road.size()) {
|
|
++owner_->point_idx;
|
|
} else {
|
|
owner_->road_idx = rand() % owner_->room->GetMapMeta()->moba_path_points.size();
|
|
owner_->point_idx = 0;
|
|
owner_->path_dir = owner_->path_dir == 1 ? 0 : 1;
|
|
}
|
|
if (owner_->path_dir == 1) {
|
|
out_point0 = std::get<0>(road.at(road.size() - owner_->point_idx - 1))->pos;
|
|
} else {
|
|
out_point0 = std::get<0>(road.at(owner_->point_idx))->pos;
|
|
out_point0 += dir * (float)a8::RandEx(0, 100);
|
|
}
|
|
if (owner_->GetPos().Distance2D2(out_point0) > 500) {
|
|
std::vector<std::tuple<std::shared_ptr<mt::WorldObject>, int, int>> paths;
|
|
int r = 0;
|
|
for (auto& road : GetRoom()->GetMapMeta()->moba_path_points) {
|
|
if (owner_->path_dir == 1) {
|
|
int p = 0;
|
|
for (auto itr = road.rbegin(); itr != road.rend(); ++itr) {
|
|
auto& point = std::get<0>(*itr);
|
|
if (point->pos.x < owner_->GetPos().GetX()) {
|
|
if (owner_->GetPos().Distance2D2(point->pos) < 500) {
|
|
paths.push_back(std::make_tuple
|
|
(
|
|
point,
|
|
r,
|
|
p
|
|
));
|
|
}
|
|
break;
|
|
}
|
|
++p;
|
|
}
|
|
} else {
|
|
int p = 0;
|
|
for (auto itr = road.begin(); itr != road.end(); ++itr) {
|
|
auto& point = std::get<0>(*itr);
|
|
if (point->pos.x > owner_->GetPos().GetX()) {
|
|
if (owner_->GetPos().Distance2D2(point->pos) < 500) {
|
|
paths.push_back(std::make_tuple
|
|
(
|
|
point,
|
|
r,
|
|
p
|
|
));
|
|
}
|
|
break;
|
|
}
|
|
++p;
|
|
}
|
|
}
|
|
++r;
|
|
}
|
|
if (paths.empty()) {
|
|
std::shared_ptr<std::tuple<std::shared_ptr<mt::WorldObject>, int, int>> path;
|
|
int r = 0;
|
|
for (auto& road : GetRoom()->GetMapMeta()->moba_path_points) {
|
|
int p = 0;
|
|
for (auto itr = road.begin(); itr != road.end(); ++itr) {
|
|
auto& point = std::get<0>(*itr);
|
|
if (!path) {
|
|
path = std::make_shared<std::tuple<std::shared_ptr<mt::WorldObject>, int, int>>
|
|
(
|
|
std::make_tuple
|
|
(
|
|
point,
|
|
r,
|
|
p
|
|
)
|
|
);
|
|
} else {
|
|
if (owner_->GetPos().Distance2D2(point->pos) <
|
|
owner_->GetPos().Distance2D2(std::get<0>(*path)->pos)) {
|
|
|
|
}
|
|
}
|
|
++p;
|
|
}
|
|
++r;
|
|
}
|
|
if (!path) {
|
|
abort();
|
|
}
|
|
paths.push_back(*path);
|
|
}
|
|
auto& path = paths.at(rand() % paths.size());
|
|
owner_->road_idx = std::get<1>(path);
|
|
owner_->point_idx = std::get<2>(path);
|
|
if (owner_->path_dir == 1) {
|
|
out_point0 = std::get<0>(road.at(road.size() - owner_->point_idx - 1))->pos;
|
|
} else {
|
|
out_point0 = std::get<0>(road.at(owner_->point_idx))->pos;
|
|
out_point0 += dir * (float)a8::RandEx(0, 100);
|
|
}
|
|
}
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
|
|
int HeroAgent::SearchPickupObj()
|
|
{
|
|
if (!owner_->IsHuman()) {
|
|
return 0;
|
|
}
|
|
Entity* nearest_obj = nullptr;
|
|
owner_->TraverseAllLayerEntityList
|
|
(
|
|
[this, &nearest_obj] (Entity* e, bool& stop) mutable
|
|
{
|
|
if (abandon_pickup_hash_.find(e->GetUniId()) !=
|
|
abandon_pickup_hash_.end()) {
|
|
return;
|
|
}
|
|
if (!nearest_obj) {
|
|
nearest_obj = e;
|
|
return;
|
|
}
|
|
if (e->GetPos().ManhattanDistance2D(owner_->GetPos()) <
|
|
nearest_obj->GetPos().ManhattanDistance2D(owner_->GetPos())) {
|
|
nearest_obj = e;
|
|
return;
|
|
}
|
|
if (e->IsCar()) {
|
|
} else if (e->IsRoomObstacle()) {
|
|
} else if (e->IsLoot()) {
|
|
}
|
|
});
|
|
owner_->TraverseCreatures
|
|
(
|
|
[this, &nearest_obj] (Creature* e, bool& stop) mutable
|
|
{
|
|
if (abandon_pickup_hash_.find(e->GetUniId()) !=
|
|
abandon_pickup_hash_.end()) {
|
|
return;
|
|
}
|
|
if (!e->IsCar()) {
|
|
return;
|
|
}
|
|
if (!e->AsCar()->HasOil()) {
|
|
return;
|
|
}
|
|
if (!e->AsCar()->CanGetOn(owner_->AsHuman())) {
|
|
return;
|
|
}
|
|
if (!nearest_obj) {
|
|
nearest_obj = e;
|
|
return;
|
|
}
|
|
if (e->GetPos().ManhattanDistance2D(owner_->GetPos()) <
|
|
nearest_obj->GetPos().ManhattanDistance2D(owner_->GetPos())) {
|
|
nearest_obj = e;
|
|
return;
|
|
}
|
|
if (e->IsCar()) {
|
|
} else if (e->IsRoomObstacle()) {
|
|
} else if (e->IsLoot()) {
|
|
}
|
|
});
|
|
if (nearest_obj &&
|
|
nearest_obj->GetPos().ManhattanDistance2D(owner_->GetPos()) < 600) {
|
|
int obj_type = 0;
|
|
if (nearest_obj->IsCar()) {
|
|
obj_type = 1;
|
|
} else if (nearest_obj->IsRoomObstacle()) {
|
|
obj_type = 2;
|
|
} else if (nearest_obj->IsLoot()) {
|
|
obj_type = 2;
|
|
}
|
|
curr_pickup_obj_ = nearest_obj->GetEntityWeakPtrRef();
|
|
out_point0 = nearest_obj->GetPos().ToGlmVec3();
|
|
return obj_type;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool HeroAgent::PickupObjIsValid()
|
|
{
|
|
if (curr_pickup_obj_.Get() && owner_->IsHuman()) {
|
|
if (curr_pickup_obj_.Get()->IsLoot()) {
|
|
Loot* loot = curr_pickup_obj_.Get()->AsLoot();
|
|
return !loot->pickuped;
|
|
} else if (curr_pickup_obj_.Get()->IsRoomObstacle()) {
|
|
RoomObstacle* ob = curr_pickup_obj_.Get()->AsRoomObstacle();
|
|
return true;
|
|
} else if (curr_pickup_obj_.Get()->IsCar()) {
|
|
if (owner_->HasBuffEffect(kBET_Driver) ||
|
|
owner_->HasBuffEffect(kBET_Passenger)) {
|
|
return false;
|
|
} else {
|
|
Car* car = curr_pickup_obj_.Get()->AsCar();
|
|
if (!car->HasOil()) {
|
|
return false;
|
|
}
|
|
if (car->CanOn(owner_->AsHuman())) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void HeroAgent::AbandonPickup(int min_time, int max_time)
|
|
{
|
|
if (curr_pickup_obj_.Get()) {
|
|
int val = a8::RandEx(min_time, max_time);
|
|
int obj_uniid = curr_pickup_obj_.Get()->GetUniId();
|
|
abandon_pickup_hash_[obj_uniid]= obj_uniid;
|
|
owner_->room->xtimer.SetTimeoutWpEx
|
|
(
|
|
val / FRAME_RATE_MS,
|
|
[this, obj_uniid] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
abandon_pickup_hash_.erase(obj_uniid);
|
|
}
|
|
},
|
|
&owner_->xtimer_attacher);
|
|
}
|
|
curr_pickup_obj_.Reset();
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::Pickup()
|
|
{
|
|
PRE_ENTER_COROUTINE();
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
int pickup_time = a8::RandEx(200, 500);
|
|
auto co = std::make_shared<BtCoroutine>(context, co_id, "Pickup");
|
|
co->runing_cb =
|
|
[this, context, pickup_time] (BtCoroutine* co)
|
|
{
|
|
if (co->IsAbort()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (owner_->HasBuffEffect(kBET_Vertigo)) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!PickupObjIsValid()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!owner_->IsHuman()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if ((GetRoom()->GetFrameNo() - context->frameno) * FRAME_RATE_MS < pickup_time) {
|
|
return behaviac::BT_RUNNING;
|
|
}
|
|
if (curr_pickup_obj_.Get()->IsLoot()) {
|
|
Loot* loot = curr_pickup_obj_.Get()->AsLoot();
|
|
owner_->AsHuman()->LootInteraction(loot);
|
|
} else if (curr_pickup_obj_.Get()->IsRoomObstacle()) {
|
|
RoomObstacle* ob = curr_pickup_obj_.Get()->AsRoomObstacle();
|
|
owner_->AsHuman()->ObstacleInteraction(ob);
|
|
} else if (curr_pickup_obj_.Get()->IsCar()) {
|
|
if (owner_->HasBuffEffect(kBET_Driver) ||
|
|
owner_->HasBuffEffect(kBET_Passenger)) {
|
|
return behaviac::BT_FAILURE;
|
|
} else {
|
|
Car* car = curr_pickup_obj_.Get()->AsCar();
|
|
owner_->AsHuman()->DoGetOn(car->GetUniId());
|
|
if (owner_->GetCar()) {
|
|
owner_->GetCar()->SetAttackDir(owner_->GetAttackDir());
|
|
}
|
|
}
|
|
}
|
|
AbandonPickup(1000 * 30, 1000 * 60);
|
|
return behaviac::BT_SUCCESS;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
bool HeroAgent::CanThrowItem(int slot)
|
|
{
|
|
if (owner_->downed) {
|
|
return false;
|
|
}
|
|
if (owner_->IsCar()) {
|
|
return false;
|
|
}
|
|
if (owner_->HasBuffEffect(kBET_Jump) ||
|
|
owner_->HasBuffEffect(kBET_Fly)) {
|
|
return false;
|
|
}
|
|
if (owner_->GetActionType() == AT_Reload ||
|
|
owner_->GetActionType() == AT_Rescue ||
|
|
owner_->GetActionType() == AT_UseItem ||
|
|
owner_->GetActionType() == AT_Relive) {
|
|
return false;
|
|
}
|
|
|
|
if (!(slot == IS_FRAG || slot == IS_SMOKE || slot == IS_MOLOTOR_COCKTAIL)) {
|
|
return false;
|
|
}
|
|
if (slot > 0 && slot < owner_->weapons.size()) {
|
|
Weapon& weapon = owner_->weapons[slot];
|
|
if (weapon.weapon_idx != 0 &&
|
|
weapon.meta &&
|
|
weapon.ammo > 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
behaviac::EBTStatus HeroAgent::ThrowItem(int slot)
|
|
{
|
|
if (!CanThrowItem(slot)) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!current_target_agent->IsValid()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (slot > 0 && slot < owner_->weapons.size()) {
|
|
Weapon& weapon = owner_->weapons[slot];
|
|
if (weapon.weapon_idx != 0 &&
|
|
weapon.meta &&
|
|
weapon.ammo > 0) {
|
|
//return true;
|
|
}
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
bool HeroAgent::SearchTeammate(int range)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float HeroAgent::GetTeammateDistance()
|
|
{
|
|
return 0;
|
|
}
|